/*
 * Copyright (c) xxxx-xxxx, Huan
 * SPDX-License-Identifier: Apache-2.0
 *
 * bilibili UID:179895513
 *
 * Date           Author       Notes
 * 2023-04-27     Huan       the first version
 */
#include "spi_drv.h"

#include "screen.h"
#include "g_io_manage.h"


#define IPS_Display_X   240
#define IPS_Display_Y   320

typedef enum
{
    Reset = 0,
    Set = 1,
    Cmd = 0,
    Dat = 1,
}Pin_state;

typedef enum
{
    Sleep_in                = 0x10,
    Sleep_out               = 0x11,
    Display_ON              = 0x29,
    Memory_Access_Control   = 0x36, //控制显示方向,RGB_BGR
    Pixel_Format_Set        = 0x3A, //16bits_18bits
    Frame_Rate_Control_1    = 0xB1,
    Frame_Rate_Control_2    = 0xB2,
    Power_Control_1         = 0xC0,
    Power_Control_2         = 0xC1,
    VCOM_Control_1          = 0xC5,
    VCOM_Control_2          = 0xC7,
}Screen_cmd;





Screen_HandleTypedef Screen_TFT22Handle;

static Image_bufTypedef img_buf;

/*===========================================================================*/
static inline void delay_ms(uint8_t ms)
{
    rt_thread_mdelay(ms);
}
static void screen_hw_init(void)
{
}
/* 命令引脚控制 *//* 高:数据    低:命令 */
static void screen_DC(Pin_state state)      //PB10
{
    if(state) G_ioHandle.high(26);
    else      G_ioHandle.low(26);
}
/* 复位引脚控制 *//* 高:置位    低:复位 */
static void screen_REST(Pin_state state)    //PB12
{
    if(state) G_ioHandle.high(28);
    else      G_ioHandle.low(28);
}
static void SPI_dat_8(uint8_t* dat, uint16_t num)
{
    if(num == (uint32_t)NULL || dat == NULL)return;

    /* 配置成8位传输 */
    struct stm32_spi *spi_drv =  rt_container_of(SPI_Handle.SPI2dev.FM25V05->bus, struct stm32_spi, spi_bus);
    spi_drv->dma.handle_tx.Init.MemDataAlignment    = DMA_PDATAALIGN_BYTE;
    spi_drv->dma.handle_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

    SPI_Handle.SPI2dev.FM25V05->config.data_width = 8;
    SPI_Handle.SPI2dev.FM25V05->bus->ops->configure(SPI_Handle.SPI2dev.FM25V05, &SPI_Handle.SPI2dev.FM25V05->config);

    SPI_Handle.RWBytes(SPI_Handle.SPI2dev.FM25V05, dat, RT_NULL, num);
}
static void SPI_dat_16(uint16_t* dat, uint16_t num)
{
    if(num == (uint32_t)NULL || dat == NULL)return;

    /* 配置成16位传输 */
    struct stm32_spi *spi_drv =  rt_container_of(SPI_Handle.SPI2dev.FM25V05->bus, struct stm32_spi, spi_bus);
    spi_drv->dma.handle_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_HALFWORD;
    spi_drv->dma.handle_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;

    SPI_Handle.SPI2dev.FM25V05->config.data_width = 16;
    SPI_Handle.SPI2dev.FM25V05->bus->ops->configure(SPI_Handle.SPI2dev.FM25V05, &SPI_Handle.SPI2dev.FM25V05->config);

    SPI_Handle.RWBytes(SPI_Handle.SPI2dev.FM25V05, dat, RT_NULL, num);
}
/*===========================================================================*/









static void screen_W_Cmd(uint8_t val)
{
    screen_DC(Cmd);
    SPI_dat_8(&val, 1);
}
static void screen_W_8bits(uint8_t val)
{
    screen_DC(Dat);
    SPI_dat_8(&val, 1);
}
static void screen_W_16bits(uint16_t val)
{
    screen_DC(Dat);
    SPI_dat_16(&val, 1);
}
void screen_set_show_region(uint16_t Xstart,uint16_t Ystart,uint16_t Xend,uint16_t Yend)
{
    switch(Screen_TFT22Handle.ScrenDir)
    {
        case None:
        {
            screen_W_Cmd(0x2A);           //设置列区域
            screen_W_16bits(Xstart);
            screen_W_16bits(Xend);
            screen_W_Cmd(0x2B);           //设置行区域
            screen_W_16bits(Ystart);
            screen_W_16bits(Yend);
            screen_W_Cmd(0x2C);           //开始写memory
        }break;
        case Left:
        {
            screen_W_Cmd(0x2A);
            screen_W_16bits(Xstart);
            screen_W_16bits(Xend);
            screen_W_Cmd(0x2B);
            screen_W_16bits(Ystart);
            screen_W_16bits(Yend);
            screen_W_Cmd(0x2C);
        }break;
        case Right:
        {
            screen_W_Cmd(0x2A);
            screen_W_16bits(Xstart+80);
            screen_W_16bits(Xend+80);
            screen_W_Cmd(0x2B);
            screen_W_16bits(Ystart);
            screen_W_16bits(Yend);
            screen_W_Cmd(0x2C);
        }break;
        case Upon:
        {
            screen_W_Cmd(0x2A);
            screen_W_16bits(Xstart);
            screen_W_16bits(Xend);
            screen_W_Cmd(0x2B);
            screen_W_16bits(Ystart + 80);
            screen_W_16bits(Yend+80);
            screen_W_Cmd(0x2C);
        }break;
        default:
        {
            screen_W_Cmd(0x2A);
            screen_W_16bits(Xstart);
            screen_W_16bits(Xend);
            screen_W_Cmd(0x2B);
            screen_W_16bits(Ystart);
            screen_W_16bits(Yend);
            screen_W_Cmd(0x2C);
        }break;
    }
    screen_DC(Dat);
}



static void Ips_WriteImgBuf_16bit(uint16_t dat)
{
    img_buf.image_buffer[img_buf.count] = dat;
    img_buf.count++;
}
static void Ips_UpdatImgBufTo_Scren(void)
{
    screen_DC(Dat);
    SPI_dat_16(img_buf.image_buffer, img_buf.count);
    img_buf.count = 0;
}


/* 清屏 */
static void screen_clear(Screen_color color)
{
    screen_set_show_region(0, 0, IPS_Display_X-1, IPS_Display_Y-1);
    for(uint16_t i=0; i<10; i++)
    {
        for(uint16_t j=0; j<(IPS_Display_X*IPS_Display_Y/10); j++)
        {
            Ips_WriteImgBuf_16bit(color);
        }
        Ips_UpdatImgBufTo_Scren();
    }
}

extern uint32_t RPG_picture[];
static void show_picture(void)
{
    screen_set_show_region(0, 0, 240-1, 200-1);
    SPI_dat_16( (uint16_t*)RPG_picture, 24000);
    SPI_dat_16(((uint16_t*)RPG_picture)+24000, 24000);
}






/* 屏幕初始化 */
static int screen_init(void)
{
    screen_hw_init();

    screen_REST(Reset);
    delay_ms(100);
    screen_REST(Set);
    delay_ms(50);
    screen_W_Cmd(Sleep_out);

    screen_W_Cmd(Memory_Access_Control);
    /*-----------------------------------------------------------------
    1<<2:显示数据锁存顺序 MH   0:LCD refresh Left to Right     1:Right to Left
    1<<3:RGB/BGR Order    RGB  0:data translate RGB            1:BGR
    1<<4:行地址命令(y)    ML   0:LCD refresh Top to Bottom     1:Bottom to Top
    1<<5:正常/反向模式    MV   0:normal Mode                   1:reverse Mode

            从内存加载
    1<<6:列显示(x)        MX   0: <——x                         1:x——>
    1<<7:行显示(y)        MY   0: |v                           1:|^
    ips_writeData((1<<7) | (1<<6) | (1<<5) | (1<<4) | (1<<3) | (1<<2));
    -----------------------------------------------------------------*/
    switch(Screen_TFT22Handle.ScrenDir)
    {
        case None: screen_W_8bits(0x48);
            break;
        case Left: screen_W_8bits(0x20);
            break;
        case Right:screen_W_8bits(0xE0);
            break;
        case Upon: screen_W_8bits(0x80);
            break;
        default:   screen_W_8bits(0x48);break;
    }

    screen_W_Cmd(Pixel_Format_Set);
    screen_W_8bits(0x55);

    screen_W_Cmd(Power_Control_1);
    screen_W_8bits(0x34); //GVDD ≦ (DDVDH - 0.2) V.

    screen_W_Cmd(Power_Control_2);
    screen_W_8bits(0x11); //Low consumption

    screen_W_Cmd(Display_ON);

    screen_clear(Blue);

    return 0;
}
static int rt_screen_init(void)
{
    Screen_TFT22Handle.ScrenDir = None;
    Screen_TFT22Handle.clear    = screen_clear;
    Screen_TFT22Handle.show_img = show_picture;

    screen_init();

    return RT_EOK;
}

#include "rtdef.h"
INIT_DEVICE_EXPORT(rt_screen_init);
